home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / NeoIntroAlone3.0 folder / Standalone / Laughs / Source / CNameIndex.cp < prev    next >
Encoding:
Text File  |  1994-08-08  |  10.4 KB  |  344 lines  |  [TEXT/KAHL]

  1. /************************************************************
  2.  *
  3.  *    Created: Sunday, January 20, 1991 4:11:08 PM
  4.  *    CNameIndex.cp
  5.  *    C++ class implementation for name-based index class
  6.  *
  7.  *
  8.  *    Copyright Neologic Systems 1992-1994
  9.  *    All rights reserved
  10.  *
  11.  *
  12.  * Within a class, references to permanent objects are kept in
  13.  * a sorted list called an index. The default sorting order in
  14.  * an index is ascending by ID value, however other sorting
  15.  * orders are possible. The class CNameIndex implements a
  16.  * secondary index which organizes objects in ascending order
  17.  * by name.
  18.  *
  19.  ***********************************************************/
  20.  
  21. #ifdef qNeoMacintosh
  22. #include <Packages.h>
  23. #endif
  24. #include "NeoTypes.h"
  25. #include CNeoMetaClassH
  26. #include CNeoSelectH
  27. #include CNeoStreamH
  28. #include CNeoDatabaseH
  29. #include "CNameIndex.h"
  30. #include CNeoClassH
  31. #include "CPerson.h"
  32.  
  33. #ifndef NeoInherited
  34. #define NeoInherited    CNeoNode
  35. #endif
  36.  
  37. /* ****************************************************************** */
  38.                         /** Instance Methods **/
  39. /* ****************************************************************** */
  40.  
  41. #pragma segment NeoCreate
  42. CNameIndex::CNameIndex(const short aCount, CNeoNode *aParent, const NeoID aID)
  43.     : CNeoNode(aCount, TRUE, aParent)
  44. {
  45.     fID = aID;
  46. }
  47.  
  48. /*
  49.  * Allocate and initialize a new instance.
  50.  */
  51. #pragma segment NeoCreate
  52. CNeoPersist *CNameIndex::New(void)
  53. {
  54.     CNameIndex *    object;
  55.  
  56.     object = new CNameIndex(0, nil, 0);
  57.  
  58.     return object;
  59. }
  60.  
  61. /*
  62.  * Return the class ID for this kind of object.
  63.  */
  64. #pragma segment NeoInfo
  65. NeoID CNameIndex::getClassID(void) const
  66. {
  67.     return kNameIndexID;
  68. }
  69.  
  70. /*
  71.  * The getEntryValue method can be used to obtain the value of a data member of
  72.  * the entry referred to by aIndex. The aName argument is a tag which identifies
  73.  * the data member, and aType refers to the format in which the value is to be
  74.  * returned. Finally, aValue is a pointer to a buffer into which the value should
  75.  * be returned.
  76.  */
  77. #pragma segment NeoSearch
  78. OSErr CNameIndex::getEntryValue(const short aIndex, const NeoTag aName, const NeoTag aType, void *aValue)
  79. {
  80.     OSErr    err        = noErr;
  81.  
  82.     NeoAssert(aIndex >= 0 && aIndex < fCount);
  83.     switch (aName) {
  84.     case pNeoName:
  85.         NeoAssert(aType == kNeoNativeStringType);
  86.         *(CNeoString *)aValue = fEntry[aIndex].fName;
  87.         break;
  88.  
  89.     case pNeoID:
  90.         NeoAssert(aType == kNeoLongType);
  91.         *(NeoID *)aValue = fEntry[aIndex].fID;
  92.         break;
  93.  
  94.     default:
  95.         err = NeoInherited::getEntryValue(aIndex, aName, aType, aValue);
  96.     }
  97.  
  98.     return err;
  99. }
  100.  
  101. /*
  102.  * Return the size of the object in memory.
  103.  */
  104. #pragma segment NeoInfo
  105. long CNameIndex::getLength(void) const
  106. {
  107.     return sizeof(CNameIndex);
  108. }
  109.  
  110. /*
  111.  * This method returns the amount of file space the object occupies in the file. It
  112.  * differs from the getLength in that getLength returns the size of the object in
  113.  * memory.
  114.  */
  115. #pragma segment NeoInfo
  116. long CNameIndex::getFileLength(void) const
  117. {
  118.     return (kNeoNodeFileLength + (sizeof(NameIndexEntry) * kNeoDefaultNodeEntryCount));
  119. }
  120.  
  121. /* ****************************************************************** */
  122.                         /** I/O Methods **/
  123. /* ****************************************************************** */
  124.  
  125. /*
  126.  * The readObject method is used to read in the permanent data members of the
  127.  * object from the given stream. In most cases, this method operates without concern
  128.  * for the type of stream the data values are coming from. As a result, this method
  129.  * is capable of reading from such diverse sources as the data fork of a file, a
  130.  * resource fork, an AppleEvent, the clipboard, a memory block, and so on.
  131.  *
  132.  * The aTag argument indicates how much information to read from the stream.
  133.  * It is sometimes sufficient to read in a minimum amount of data and have all
  134.  * other data be read in on demand. Other times it is necessary to read all the
  135.  * data immediately as the stream may not be available later.
  136.  *
  137.  * The two tag values that are currently used are kNeoObjectTag and kNeoAllTag.
  138.  *
  139.  * The value kNeoObjectTag means that only those values of immediate interest
  140.  * need to be read from the stream, though implementations of readObject may read
  141.  * in additional data member values if they wish.
  142.  *
  143.  * The value kNeoAllTag indicates that all data member values for this class
  144.  * should be read in to the stream.
  145.  */
  146. #pragma segment NeoRead
  147. void CNameIndex::readObject(CNeoStream *aStream, const NeoTag aTag)
  148. {
  149.     short    index;
  150.  
  151.     NeoInherited::readObject(aStream, aTag);
  152.  
  153.     for (index = 0; index < fCount; index++) {
  154.         fEntry[index].fID = aStream->readLong();
  155.         aStream->readNativeString(fEntry[index].fName, sizeof(fEntry[index].fName));
  156.     }
  157. }
  158.  
  159. /*
  160.  * The writeObject method is used to write to the permanent data members of the
  161.  * object from the given stream. In most cases, this method operates without concern
  162.  * for the type of stream the data values are coming from. As a result, this method
  163.  * is capable of writing to such diverse sources as the data fork of a file, a
  164.  * resource fork, an AppleEvent, the clipboard, a memory block, and so on.
  165.  *
  166.  * The aTag argument indicates how much information to write to the stream.
  167.  * It is sometimes sufficient to write out only those parts that are dirty. Other
  168.  * times it is necessary to write all the data, as when doing Save As operation
  169.  * or when communicating an object's complete state across and RPC channel.
  170.  *
  171.  * The two tag values that are currently used are kNeoObjectTag and kNeoAllTag.
  172.  *
  173.  * The value kNeoObjectTag means that only those values of immediate interest
  174.  * need to be written to the stream, though implementations of writeObject may
  175.  * write out additional data member values if they wish.
  176.  *
  177.  * The value kNeoAllTag indicates that all data member values for this class
  178.  * should be writen out to the stream.
  179.  */
  180. #pragma segment NeoWrite
  181. void CNameIndex::writeObject(CNeoStream *aStream, const NeoTag aTag)
  182. {
  183.     short    index;
  184.  
  185.     NeoInherited::writeObject(aStream, aTag);
  186.  
  187.     for (index = 0; index < fCount; index++) {
  188.         aStream->writeLong(fEntry[index].fID);
  189.         aStream->writeNativeString(fEntry[index].fName, sizeof(fEntry[index].fName));
  190.     }
  191. }
  192.  
  193. /* ****************************************************************** */
  194.                 /** Object List Management Methods **/
  195. /* ****************************************************************** */
  196.  
  197.  
  198. /*
  199.  * This method reads in the object referred to by the specified entry. Secondary
  200.  * indices do not refer directly to the object in the file or in memory. Instead,
  201.  * the specified entry of this index contains the information necessary to
  202.  * locate the object using the primary index.
  203.  *
  204.  * Note: The getObject method is not supposed to add a reference to the object.
  205.  * As such, the reference added by FindByID is removed before passing the object
  206.  * back to our caller.
  207.  */
  208. #pragma segment NeoSearch
  209. CNeoPersist *CNameIndex::getObject(const short aIndex)
  210. {
  211.     CNeoPersist *    object;
  212.     CNeoIDSelect    key(fEntry[aIndex].fID);
  213.  
  214.     object = (CNeoPersist *)CNeoClass::FindObject(CNeoMetaClass::FObjClassID, &key, FALSE, nil, nil);
  215.     object->unrefer();                // Our caller will add the reference if it wants to
  216.  
  217.     return object;
  218. }
  219.  
  220. /*
  221.  * This method locates the leaf of the index tree into which the object
  222.  * should be added. Then it fills in the attributes of the new entry and calls
  223.  * insertEntry() to add it in the proper place in the list.
  224.  */
  225. #pragma segment NeoAdd
  226. CNeoNode *CNameIndex::insertObject(const short aIndex, CNeoPersist *aObject)
  227. {
  228.     NeoID            oldClassID;
  229.     CNeoNode *        newRoot        = nil;
  230.     CPerson *        person        = (CPerson *)aObject;
  231.     CNeoString        name;
  232.     NameIndexEntry    newEntry;
  233.  
  234.     newEntry.fID = person->fID;
  235.     ((CPerson *)aObject)->getName(newEntry.fName);
  236.  
  237.     oldClassID = CNeoMetaClass::FSysClassID;
  238.     CNeoMetaClass::FSysClassID = kNameIndexID;
  239.  
  240.     newRoot = insertEntry(aIndex, (Ptr)&newEntry);
  241. #ifdef qNeoDebug
  242.     if (newRoot)
  243.         NeoVerifyNode(newRoot);
  244. #endif
  245.  
  246.     CNeoMetaClass::FSysClassID = oldClassID;
  247.  
  248.     return newRoot;
  249. }
  250.  
  251. /*
  252.  * The metaclass object of all persistent classes need to be able to determine
  253.  * the primary selection criteria of that class. This static function is called
  254.  * through the index class's metaclass object. It is used to: 1) whether the
  255.  * index can perform a binary search using the given select key, and 2) to
  256.  * obtain a select key for locating the proper index entry for the given
  257.  * object.
  258.  */
  259. #pragma segment NeoSearch
  260. void *CNameIndex::KeyManager(const NeoKeyOp aOp, ...)
  261. {
  262.     va_list            argptr;                    // pointer to argument list.
  263.     NeoSelectType    selectType;
  264.     void *            value    = nil;
  265.     CNeoSelect *    key;
  266.     CPerson *        person;
  267.     CNeoString        name;
  268.  
  269.     va_start(argptr, aOp);
  270.     switch (aOp) {
  271.     case kNeoCanSupport:
  272.         key = va_arg(argptr, CNeoSelect *);
  273.         selectType = key->getSelectType();
  274.         if (selectType == pNeoName)
  275.             value = (void *)(unsigned  char)TRUE;
  276. #ifdef qNeoShare
  277.         else if (selectType == kNeoAEKeySelect &&
  278.                  ((CNeoAEKeySelect *)key)->getAEKeyword() == pNeoName)
  279.             value = (void *)(unsigned  char)TRUE;
  280. #endif
  281.         else
  282.             value = NeoInherited::KeyManager(kNeoCanSupport, key, selectType);
  283.         break;
  284.  
  285.     case kNeoGetKey:
  286.         person = va_arg(argptr, CPerson *);
  287.         person->getName(name);
  288.         value = (void *)new CNeoNameSelect(name);
  289.         break;
  290.     }
  291.     va_end(argptr);
  292.  
  293.     return value;
  294. }
  295.  
  296. /* ****************************************************************** */
  297.                 /** Entry Management Methods **/
  298. /* ****************************************************************** */
  299.  
  300. /*
  301.  * This function provides a mechanism for determining the size of entries for
  302.  * a particular node.
  303.  */
  304. #pragma segment NeoChange
  305. short CNameIndex::getEntrySize(void) const
  306. {
  307.     return sizeof(NameIndexEntry);
  308. }
  309.  
  310. #ifdef qNeoDebug
  311. /* ****************************************************************** */
  312.                         /** Debugging Methods **/
  313. /* ****************************************************************** */
  314.  
  315. /*
  316.  * All subclasses of CNeoPersist should override the verify method to
  317.  * perform a consistency check on objects. This method should make as
  318.  * many general assertions as possible.
  319.  *
  320.  * CNeoParentNNameIndex's verify checks that the entries are sorted
  321.  * in ascending order by the fields fParentID and fName.
  322.  * aValue is assumed to be a pointer to the last entry in the previous
  323.  * sibling node.
  324.  * The return value is a pointer to the last entry in this node.
  325.  */
  326. const void *CNameIndex::verify(const void *aValue) const
  327. {
  328.     short                    index;
  329.     const NameIndexEntry *    entry    = (NameIndexEntry *)aValue;
  330.  
  331.     for (index = 0; index < fCount; index++) {
  332.         if (entry)
  333.             NeoAssert(entry->fName <= fEntry[index].fName);
  334.         entry = &fEntry[index];
  335.     }
  336.  
  337.     // CNeoNode::verify assumes parameter to be the current size of the database
  338.     NeoInherited::verify(nil);
  339.  
  340.     return entry;
  341. }
  342. #endif
  343.  
  344.